﻿using System;
using System.Collections.Generic;
using System.Configuration;
using System.Linq;
using System.Web.Mvc;
using Localization;
using SinBiota.Model.Business.AuthenticationServices.Interfaces;
using SinBiota.Model.Business.PersistenceServices.Interfaces;
using SinBiota.Model.Entities;
using Sinbiota.Web.Models;

namespace Sinbiota.Web.Controllers
{
    public class TaxonomyController : BaseController
    {
        private static readonly int TaxonomyViewDepth = Convert.ToInt32(ConfigurationManager.AppSettings["TaxonomyViewDepth"]);
        private readonly ITaxonPersistenceServices _taxonPersistenceServices;
        private readonly IPermissionServices _permissionServices;
        private readonly IUserPersistenceServices _userPersistenceServices;

        public TaxonomyController(ITaxonPersistenceServices taxonPersistenceServices, IPermissionServices permissionServices, IUserPersistenceServices userPersistenceServices)
        {
            _taxonPersistenceServices = taxonPersistenceServices;
            _userPersistenceServices = userPersistenceServices;
            _permissionServices = permissionServices;
        }

        //
        // GET: /Taxonomy/
        public ActionResult Index()
        {
            return View(_taxonPersistenceServices.FindAllRootNodes());
        }

        //
        // GET: /Taxonomy/Details/5
        public ActionResult Details(int? id)
        {
            var taxon = _taxonPersistenceServices.FindById(id ?? 1);
            var ancestors = _taxonPersistenceServices.FindAncestors(taxon);
            return taxon == null ? View("NotFound") : View(new TaxonDetailsModel(taxon, TaxonomyViewDepth, ancestors, _permissionServices.CanAddTaxonChildren(User.Identity.Name, taxon)));
        }


        public ActionResult Create(int id)
        {
            var parent = _taxonPersistenceServices.FindById(id);
            if (!_permissionServices.CanAddTaxonChildren(User.Identity.Name, parent)) return View("NonAuthorized");
            
            return parent == null ? View("NotFound") : View(new TaxonCreateModel{Parent = parent});
        }

        [HttpPost]
        public ActionResult Create(TaxonCreateModel model)
        {
            var parent = _taxonPersistenceServices.FindById(model.Parent.Id);
            if (!_permissionServices.CanAddTaxonChildren(User.Identity.Name, parent)) return View("NonAuthorized");

            if (ModelState.IsValid)
            {
                // check if taxon already exists:
                if (_taxonPersistenceServices.FindChildren(parent).Any(x => x.Name.Equals(model.TaxonName)))
                {
                    ModelState.AddModelError("Name", Messages.TaxonAlreadyExists);
                    return View(model);
                }
                var taxon = new Taxon
                                {
                                    IncludedByUser = _userPersistenceServices.FindByUsername(User.Identity.Name),
                                    Name = model.TaxonName,
                                    Rank = model.TaxonRank,
                                    Parent = parent,
                                    TaxonReference = _taxonPersistenceServices.FindReferenceByExactNameOrCreate(model.TaxonReference)
                                };
                _taxonPersistenceServices.Save(taxon);
                SetInformationMessage(Messages.OperationCompletedSuccessfully);
                return RedirectToAction("Details", new {id = taxon.Id});
            }
            return View(model);
        }



        [HttpPost]
        public ActionResult Search(FormCollection collection)
        {
            return View(_taxonPersistenceServices.FindByNameLike(collection[SearchBoxName]));
        }

        public ActionResult Lineage(int id)
        {
            if (Request.IsAjaxRequest())
            {
                var taxon = _taxonPersistenceServices.FindById(id);
                var ancestors = _taxonPersistenceServices.FindAncestors(taxon);
                return taxon == null
                           ? View("NotFound")
                           : View(new TaxonDetailsModel(taxon, TaxonomyViewDepth, ancestors));
            }
            return RedirectToAction("Details", new {id});
       }

        ////AJAX
        public JsonResult GetChildren(int id)
        {
            var parent = _taxonPersistenceServices.FindById(id);
            return parent == null ?
                Json(JsonMessage.ErrorMessage("Parent taxon not found...")) : 
                    Json(_taxonPersistenceServices.FindChildren(parent).Select(x => new { x.Id, x.Name, x.Rank }).OrderBy(x => x.Name));
        }

        public JsonResult GetRootNodes()
        {
            return Json(_taxonPersistenceServices.FindAllRootNodes().Select(x => new { x.Id, x.Name, x.Rank }).OrderBy(x => x.Name));
        }

        //AJAX
        public JsonResult AutoComplete(string term, int count = 50)
        {
            var split = term.Split(' '); // separate genus and species, if that is the case;
            
            // search genus;
            var genus = split.Length == 1 ? _taxonPersistenceServices.FindByNameStartswithAndRank(split[0], COLRank.Genus).OrderBy(x => x.Name)
                : _taxonPersistenceServices.FindByNameAndRank(split[0],COLRank.Genus).OrderBy(x => x.Name);
            var result = new List<Taxon>();
            // add the children (species) of each genus:
            foreach (var children in genus.Select(taxon => _taxonPersistenceServices.FindChildren(taxon)))
            {
                // if the species was informed, filter; otherwise, all children is added;
                result.AddRange(split.Length > 1 ? children.Where(x => x.Name.StartsWith(split[1])).ToList() : children);
            }
            return Json(result.Select(t => new { id = t.Id, label = t.ScientificName(), description = t.Rank }).OrderBy(x => x.label), JsonRequestBehavior.AllowGet);
        }

    }
}
